package net.cathackers.devel.scmp.chat.impl.xmpp.messageComponent;

import org.apache.log4j.Logger;
import org.dom4j.Document;

import net.cathackers.devel.scmp.auth.impl.jabber.JabberUserID;
import net.cathackers.devel.scmp.auth.interfaces.UserID;
import net.cathackers.devel.scmp.chat.factories.ChatServiceFactory;
import net.cathackers.devel.scmp.chat.impl.ManagedQueueImpl;
import net.cathackers.devel.scmp.chat.impl.xmpp.iqcomponent.interfaces.XMPPComponent;
import net.cathackers.devel.scmp.chat.interfaces.ChatConfiguration;
import net.cathackers.devel.scmp.chat.interfaces.ChatManager;
import net.cathackers.devel.scmp.chat.interfaces.GroupChatManager;
import net.cathackers.devel.scmp.chat.interfaces.ManagedQueue;
import net.cathackers.devel.scmp.factories.SCMPFactory;
import net.cathackers.devel.scmp.xmpp.MessagePacket;
import net.cathackers.devel.scmp.xmpp.Packet;
import net.cathackers.devel.scmp.xmpp.StanzaErrors;

public class MessageComponent extends XMPPComponent<Packet> {
    private ChatManager chatManager_;
    private OfflineMessageStore messageStore_;
    private ManagedQueue<Packet> offlineQueue_;
    private GroupChatManager groupChatManager_;
    private Logger logger_;

    public MessageComponent(OfflineMessageStore store) {
	this.chatManager_ = SCMPFactory.getChatManager();
	this.groupChatManager_ = ChatServiceFactory.getGroupchatManager();
	this.messageStore_ = store;
	this.offlineQueue_ = new ManagedQueueImpl<Packet>(
		new OfflineDeliveryProcessor(store), 2);
	logger_ = SCMPFactory.getLogger(this);
    }

    @Override
    public void process(Packet originalPacket) {
	MessagePacket packet = (MessagePacket) originalPacket;
	logger_.debug("the MessageComponent received a packet");
	if (packet != null) {
	    switch (packet.getMessageType()) {
	    case normal:
	    case chat:
		if (groupChatManager_.isGroupChatRequest(packet)) {
		    groupChatManager_.handleMessage(packet);
		} else {
		    this.handleChatMessages(packet);  
		}
		break;
	    case groupchat:
		if (groupChatManager_.isGroupChatRequest(packet)) {
		    groupChatManager_.handleMessage(packet);
		}
		break;
	    default:
		// drop the packet
		return;
	    }
	}
    }

    private void handleChatMessages(MessagePacket packet) {
	boolean isOnline = chatManager_.checkIfSessionOnline(packet.getTo());
	if (isOnline == true) {
	    logger_.debug("the recipient is online");
	    chatManager_.deliverToUser(packet);
	} else {
	    UserID jidWithoutResource = packet.getTo().getGeneralUserID();
	    boolean isAnyResourceAvailable = chatManager_
		    .checkIfSessionOnline(jidWithoutResource);
	    packet.setTo(jidWithoutResource);
	    if (isAnyResourceAvailable) {
		logger_.debug("there is a resource available");
		chatManager_.deliverToUser(packet);
	    } else {
		try {
		    logger_.debug("the message will be stored offline");
		    messageStore_.storeOfflineMessage(packet);
		} catch (OfflineStoreIsFullException e) {
		    // return service unavailable error to the sender
		    MessagePacket errorPacket = getError(packet);
		    chatManager_.deliverToUser(errorPacket);
		}
	    }
	}
    }

    public void deliverToBackup(Document doc) {
	if (doc != null) {

	    offlineQueue_.enqueue(new MessagePacket(doc));
	} else {
	    return;
	}
    }

    private MessagePacket getError(MessagePacket packet) {
	StanzaErrors error = new StanzaErrors(
		StanzaErrors.Condition.service_unavailable);
	packet.setError(error);
	packet.setTo(packet.getFrom());
	ChatConfiguration config = SCMPFactory.getConfiguration();
	packet.setFrom(new JabberUserID(config.getChatServerDomain()));
	return packet;
    }
}
